#include "Room.h"

#include "Player.h"

#include <algorithm>
#include <iostream>


Room::Room(int x, int y) :
	GameObject(x, y, Type_Room)
{
	addRandomContent();
}


bool Room::isPassable(const GameObject* gameObject) const
{
	return gameObject->getType() == Type_Player;
}


void Room::handleCollision(GameObject* gameObject)
{
	if (gameObject->getType() == Type_Player)
	{
		DWORD iID;
		HANDLE RenderThread; 

		threadData.room = this;
		threadData.gameObject = gameObject;

		static_cast<Player*>(gameObject)->setIgnoreInput(true);

		// create the thread
		RenderThread = CreateThread(NULL, 0, handlePlayerInRoom, &threadData, 0, &iID);
		// check for creation errors
		if (RenderThread == NULL) 
		{
			DWORD dwError = GetLastError();
			std::cout << "Error in creating thread: "<< dwError << std::endl ;
			return;
		}
	}
}



void Room::drawObject(int row, int col) const
{
	// Door.
	drawSquare(row, col);

	std::vector<drawPoint> points;

	// Door parts.
	setColor(0.859,0.717,0.341);

	points.push_back(drawPoint(col + 0.1, row + 0.5, 0));
	points.push_back(drawPoint(col + 0.2, row + 0.6, 0));
	points.push_back(drawPoint(col + 0.3, row + 0.5, 0));
	points.push_back(drawPoint(col + 0.2, row + 0.4, 0));

	drawInMode(GL_QUADS, points);
	points.clear();
}


void Room::addGateKey()
{
	content.push_back(Content_GateKey);
}


void Room::printContent() const
{
	for (std::vector<Content>::const_iterator it = content.begin(); it != content.end(); ++it)
	{
		std::cout << "\t" << getDescription(*it) << std::endl;
	}
}


std::string Room::getActions() const
{
	std::string line("(");
	bool hasAttackableContent = false;
	bool hasTakeableContent = false;
	for (std::vector<Content>::const_iterator it = content.begin(); it != content.end(); ++it)
	{
		if (*it == Content_Monster)
			hasAttackableContent = true;
		if (*it == Content_GoldBag || Content_GateKey)
			hasTakeableContent = true;
	}
	
	if (hasAttackableContent)
	{
		line += getName(Action_Attack) + ", ";
	}
	if (hasTakeableContent)
	{
		line += getName(Action_Take) + ", ";
	}
	line += "exit)";
	return line;
}


std::string Room::getAttackableContent() const
{
	std::string line("(");
	for (std::vector<Content>::const_iterator it = content.begin(); it != content.end(); ++it)
	{
		if (*it == Content_Monster)
		{
			line += getName(*it);
			line += ", ";
		}
	}
	if (line.size() > 1)
	{
		line[line.size() - 2] = ')';
	}
	else
	{
		line.clear();
	}

	return line;
}


std::string Room::getTakeableContent() const
{
	std::string line("(");
	for (std::vector<Content>::const_iterator it = content.begin(); it != content.end(); ++it)
	{
		if (*it == Content_GoldBag || *it == Content_GateKey)
		{
			line += getName(*it);
			line += ", ";
		}
	}
	if (line.size() > 1)
	{
		line[line.size() - 2] = ')';
	}
	else
	{
		line.clear();
	}

	return line;
}


bool Room::roomContains(Content contentToFind) const
{
	return std::find(content.begin(), content.end(), contentToFind) != content.end();
}


void Room::removeContent(Content contentToRemove)
{
	if (roomContains(contentToRemove))
	{
		content.erase(std::find(content.begin(), content.end(), contentToRemove));
	}
}


std::string Room::getDescription(Content content)
{
	switch (content)
	{
	case Content_Monster: return "A goblin";
	case Content_GoldBag: return "A gold bag";
	case Content_GateKey: return "A large rusty key";
	};
	return "";
}


std::string Room::getName(Content content)
{
	switch (content)
	{
	case Content_Monster: return "goblin";
	case Content_GoldBag: return "bag";
	case Content_GateKey: return "key";
	};
	return "";
}


std::string Room::getName(Action action)
{
	switch (action)
	{
	case Action_Attack: return "attack";
	case Action_Take: return "take";
	case Action_Exit: return "exit";
	};
	return "";
}


void Room::addRandomContent()
{
	if (rand() % 2 == 0) 
	{
		content.push_back(Content_Monster);
	}
	content.push_back(Content_GoldBag);	
}


DWORD WINAPI Room::handlePlayerInRoom(LPVOID n) 
{
	ThreadData* threadData = static_cast<ThreadData*>(n);
	// Variables for convience.
	threadData->room->handlePlayerInRoom(static_cast<Player*>(threadData->gameObject));
	return 0;
}


void Room::handlePlayerInRoom(Player* player)
{
	using namespace std;	
	
	cout << player->getName() << " has entered a room." << endl;
	cout << "In the room, you see:" << endl;
	printContent();
	while (true)
	{
		cout << "What do you want to do? " << getActions() << endl;
		string action;
		cin >> action;
		if (action == getName(Action_Take))
		{
			handleTake(player);
		}
		else if (action == getName(Action_Attack))
		{
			handleAttack(player);
		}
		else if (action == "exit")
		{
			cout << "You left the room." << endl;
			break;
		}
	}
	
	player->setIgnoreInput(false);
	return;
}


void Room::handleTake(Player* player)
{
	using namespace std;
	
	if (roomContains(Content_Monster))
	{
		// Can't take the item if there is a monster in the room
		cout << "The goblin attacks you! You should defend yourself." << endl;
		return;
	}

	string takeableContent = getTakeableContent();
	if (takeableContent.empty())
	{
		// Empty room.
		cout << "This room is empty." << endl;
		return;
	}

	cout << "What do you want to take? " << takeableContent << endl;
	string target;
	cin >> target;
	if (target == getName(Content_GoldBag) && roomContains(Content_GoldBag))
	{
		int gold = (rand() % 99) + 1;
		player->addToInventory(Player::InventoryItem_Gold, gold);
		removeContent(Content_GoldBag);
	}
	else if (target == getName(Content_GateKey) && roomContains(Content_GateKey))
	{
		player->addToInventory(Player::InventoryItem_GateKey);
		removeContent(Content_GateKey);
	}
	else
	{
		cout << "Unable to take " << target;
	}
}


void Room::handleAttack(Player* player)
{
	using namespace std;
	string attackableContent = getAttackableContent();
	if (attackableContent.empty())
	{
		// No enemies.
		cout << "No monsters in the room." << endl;
		return;
	}

	cout << "What do you want to attack? " << attackableContent << endl;
	string target;
	cin >> target;
	if (target == getName(Content_Monster))
	{
		if (roomContains(Content_Monster))
		{
			cout << "You killed the goblin." << endl;
			removeContent(Content_Monster);
		}
	}
	else 
	{
		cout << "Unable to attack " << target << endl;
	}
}